package reader;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import models.state.EnvStateGraph;
import models.state.State;
import models.state.Transition;
import models.state.uml.CommentUML;
import models.state.uml.SubVertex;
import models.state.uml.TransitionUML;

// TODO: Auto-generated Javadoc
/**
 * The Class UMLReader.
 */
public class UMLReader {

    /**
     * Instantiates a new uML reader.
     */
    public UMLReader() {

    }


    /**
     * Parses the uml file.
     *
     * @param filePath the file path
     * @return the env state graph
     * @throws Exception the exception
     */
    public EnvStateGraph parseUMLFile(String filePath) throws Exception {

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setValidating(true);
        Document dom = null;
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            db.setErrorHandler(new org.xml.sax.ErrorHandler() {
                // Ignore the fatal errors
                public void fatalError(SAXParseException exception)
                        throws SAXException {
                }

                // Validation errors
                public void error(SAXParseException e) throws SAXParseException {
                    System.err.println("Error at " + e.getLineNumber()
                            + " line." + e.getMessage());
                }

                // Show warnings
                public void warning(SAXParseException warn)
                        throws SAXParseException {
                    System.err.println("Warning:" + warn.getMessage());
                }
            });

            dom = db.parse(filePath);
        } catch (ParserConfigurationException pce) {
            System.err.println(pce.getLocalizedMessage());
            throw new Exception(pce.getLocalizedMessage());
        } catch (SAXException se) {
            System.err.println(se.getLocalizedMessage());
            throw new Exception(se.getLocalizedMessage());
        } catch (IOException ioe) {
            System.err.println(ioe.getLocalizedMessage());
            throw new Exception(ioe.getLocalizedMessage());
        }
        // List<XMLLayoutConfig> xmlHomeConfigList = new ArrayList<XMLLayoutConfig> ();
        List<CommentUML> comments = new ArrayList<CommentUML>();
        NodeList allComponents = dom.getElementsByTagName("ownedComment");
        for (int i = 0; i < allComponents.getLength(); i++) {
            Element component = (Element) allComponents.item(i);
            CommentUML commentUML = parseComment(component);
            comments.add(commentUML);
        }
        
        List<TransitionUML> transitions = new ArrayList<TransitionUML>();
        allComponents = dom.getElementsByTagName("transition");
        for (int i = 0; i < allComponents.getLength(); i++) {
            Element component = (Element) allComponents.item(i);
            TransitionUML transitionUML = parseTransition(component);
            transitions.add(transitionUML);
        }
        
        List<SubVertex> subvertexs = new ArrayList<SubVertex>();
        allComponents = dom.getElementsByTagName("subvertex");
        for (int i = 0; i < allComponents.getLength(); i++) {
            Element component = (Element) allComponents.item(i);
            SubVertex vertex = parseVertex(component);
            subvertexs.add(vertex);
        }
        
        List<State> states = new ArrayList<State>();
        //link subvertex with comment
        for(SubVertex vertex : subvertexs) {
            State s = new State();
            s.setId(vertex.getId());
            List<String> substateList = new ArrayList<String>();
            s.setStates(substateList);
            //find vertex in comment
            for(CommentUML comment : comments) {
                String c[] = comment.getContent().trim().split(":");
                if(c != null && c.length >= 1 && c[0].equals(vertex.getName())) {
   
                    if(c.length >= 2) {
                        String []subss = c[1].replace("AND", ";").trim().split(";");
                        for(String subs : subss) {
                            substateList.add(subs.trim());
                        }
                    }
                    break;
                }
            }
            states.add(s);
        }
        
        
        List<Transition> trans = new ArrayList<Transition>();
        for(TransitionUML tranUML : transitions) {
            Transition tran = new Transition();
            tran.setFrom(tranUML.getSource());
            tran.setTo(tranUML.getTarget());
            List<String> actions = new ArrayList<String>();
            tran.setActions(actions);
          //find vertex in comment
            for(CommentUML comment : comments) {
                String c[] = comment.getContent().trim().split(":");
                if(c != null && c.length >= 1 && c[0].equals(tranUML.getName())) {
   
                    if(c.length >= 2) {
                        String []subss = c[1].trim().split(";");
                        for(String subs : subss) {
                            actions.add(subs.trim());
                        }
                    }
                    break;
                }
            }
            trans.add(tran);
        }
        
        //link transitions with comment
        
        EnvStateGraph graph = new EnvStateGraph();
        graph.setStates(states);
        graph.setTransitions(trans);

        return graph;
    }

    /**
     * Parses the comment.
     *
     * @param component the component
     * @return the comment uml
     */
    private CommentUML parseComment(Element component) {
        CommentUML commentUML = new CommentUML();
        commentUML.setId(component.getAttribute("xmi:id"));
        commentUML.setContent(getTextValue(component, "body"));
        return commentUML;
    }

    
    /**
     * Parses the transition.
     *
     * @param component the component
     * @return the transition uml
     */
    private TransitionUML parseTransition(Element component) {
        TransitionUML transitionUML = new TransitionUML();
        transitionUML.setId(component.getAttribute("xmi:id"));
        transitionUML.setName(component.getAttribute("name"));
        transitionUML.setSource(component.getAttribute("source"));
        transitionUML.setTarget(component.getAttribute("target"));
        return transitionUML;
    }
    
    
    private SubVertex parseVertex(Element component) {
        SubVertex vertex = new SubVertex();
        vertex.setId(component.getAttribute("xmi:id"));
        vertex.setName(component.getAttribute("name"));
        return vertex;
    }
    // /**
    // * <p> Get Component Config</p>
    // * @param component
    // * @return XMLLayoutConfig
    // */
    // private XMLLayoutConfig getComponentConfig(Element component) throws ItreeClientException{
    // try {
    // XMLLayoutConfig config = new XMLLayoutConfig();
    // config.setComponentId(getIntValue(component, "id"));
    // config.setComponentCode(getTextValue(component, "code"));
    // config.setRow(getIntValue(component, "row"));
    // config.setColumn(getIntValue(component, "column"));
    // config.setWidth(getTextValue(component, "width"));
    // config.setHeight(getTextValue(component, "height"));
    // config.setHeader(getTextValue(component, "header"));
    // config.setVisible(getBooleanValue(component,"visible"));
    // config.setCollapsible(getBooleanValue(component,"collapsible"));
    // config.setResizable(getBooleanValue(component,"resizable"));
    // config.setUrl(getTextValue(component, "url"));
    // return config;
    // } catch(Exception nfe) {
    // throw new ItreeClientException(nfe.getLocalizedMessage());
    // }
    // }
    //
    /**
     * It take a xml element and the tag name, look for the tag and get the text content i.e for
     * <employee><name>John</name></employee> xml snippet if the Element points to employee node and tagName is 'name' I
     * will return John
     *
     * @param ele the ele
     * @param tagName the tag name
     * @return the text value
     */
    private String getTextValue(Element ele, String tagName) {
        String textVal = null;
        NodeList nl = ele.getElementsByTagName(tagName);
        if (nl != null && nl.getLength() > 0) {
            Element el = (Element) nl.item(0);
            textVal = el.getFirstChild().getNodeValue();
        }
        return textVal;
    }

    // public EnvStateGraph readEnvStateTransDiagram(String filePath) throws Exception {
    // BufferedReader br = new BufferedReader(new FileReader(filePath));
    // String line;
    // EnvStateGraph graph = new EnvStateGraph();
    // List<State> stateSeg = new LinkedList<State>();
    // List<Transition> transitionSeg = new ArrayList<Transition>();
    // graph.setStates(stateSeg);
    // graph.setTransitions(transitionSeg);
    // if ((line = br.readLine()) != null) {
    // if(line.equalsIgnoreCase("States:")) {
    // while(!(line = br.readLine()).equalsIgnoreCase("Transitions:")) {
    // //read states
    // String [] idStates = line.trim().split(":");
    // if(idStates.length != 2) {
    // br.close();
    // throw new Exception("Invalid file format exception in "
    // + this.getClass().getName() + "#readEnvStateTransDiagram");
    // }
    // State state = new State();
    // state.setId(Integer.parseInt(idStates[0]));
    // String []states = idStates[1].trim().split("&");
    // List<String> statesList = new ArrayList<String>();
    // for(String s : states) {
    // statesList.add(s);
    // }
    // state.setStates(statesList);
    // stateSeg.add(state);
    // }
    // while((line = br.readLine()) != null) {
    // //read transitions
    // String []tranAct = line.trim().split(":");
    // if(tranAct.length != 2) {
    // br.close();
    // throw new Exception("Invalid file format exception in "
    // + this.getClass().getName() + "#readEnvStateTransDiagram");
    // }
    // String []fromTo = tranAct[0].trim().split("-");
    // Transition t = new Transition();
    // if(fromTo.length != 2) {
    // br.close();
    // throw new Exception("Invalid file format exception in "
    // + this.getClass().getName() + "#readEnvStateTransDiagram");
    // }
    // t.setFrom(Integer.valueOf(fromTo[0]));
    // t.setTo(Integer.valueOf(fromTo[1]));
    // String []actions = tranAct[1].trim().split(";");
    // List<String> actionList = new ArrayList<String>();
    // for(String act : actions) {
    // actionList.add(act);
    // }
    // t.setActions(actionList);
    // transitionSeg.add(t);
    // }
    // }
    // }
    // br.close();
    // return graph;
    // }
}
